/* $Id: mbd.grp.c 397 2007-11-26 19:04:00Z mblack $
 * Copyright (C) 2007 Platform Computing Inc
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 *
 */

#include <stdlib.h>
#include "mbd.h"

#define NL_SETN		10	

struct uStackEntry {
    struct gData*  myGData;
    struct uData*  myUData;
    struct gData*  parentGData;
    struct uData*  parentUData;
};

static void                    catMembers (struct gData*, char*, char);
static void                    traverseGroupTree(struct gData*);
static void                    checkuDataSet(struct uData*);
static struct groupInfoEnt*    getGroupInfoEnt(char**, int*, char);
static struct groupInfoEnt*    getGroupInfoEntFromUdata(struct uData*, char);
static void 	    	       getAllHostGroup(struct gData **, int, int,
		    	    	    	       struct groupInfoEnt *, int *);
static void    	       	       getSpecifiedHostGroup(char **, int, 
						     struct gData **, int, int,
						     struct groupInfoEnt *, 
						     int *);
static void    	       	       copyHostGroup(struct gData *, int, 
					     struct groupInfoEnt *);

LS_BITSET_T                    *allUsersSet = NULL;

LS_BITSET_T                    *uGrpAllSet;

LS_BITSET_T                    *uGrpAllAncestorSet;

int 
checkGroups (struct infoReq *groupInfoReq, 
	     struct groupInfoReply *groupInfoReply)
{
    int                   recursive;
    struct gData **        gplist;
    int                    ngrp;    

    if (groupInfoReq->options & HOST_GRP) {
        gplist = hostgroups;
        ngrp = numofhgroups;
    } else if (groupInfoReq->options & USER_GRP) {
        gplist = usergroups;
        ngrp = numofugroups;
    } else {
        return LSBE_LSBLIB;
    }

    if (groupInfoReq->options & GRP_RECURSIVE)
        recursive = TRUE;
    else
        recursive = FALSE;

    
    if (groupInfoReq->options & HOST_GRP) {
	if (groupInfoReq->options & GRP_ALL) {
	    getAllHostGroup(gplist, ngrp, recursive, groupInfoReply->groups, 
			    &groupInfoReply->numGroups);
	} else {
	    getSpecifiedHostGroup(groupInfoReq->names, groupInfoReq->numNames, 
				  gplist, ngrp, recursive, 
				  groupInfoReply->groups, 
				  &groupInfoReply->numGroups);

	    if (groupInfoReply->numGroups == 0 || 
		groupInfoReply->numGroups != groupInfoReq->numNames) {
		return (LSBE_BAD_GROUP);
	    }
	}
    }

    
    if (groupInfoReq->options & USER_GRP) {

	if (groupInfoReq->options & GRP_ALL) {
	    int num = 0;

	    groupInfoReply->groups = getGroupInfoEnt(NULL, &num, recursive);
	    groupInfoReply->numGroups = num;
		
	} else {
	    int num = 0;
	    
	    num = groupInfoReq->numNames;
	    groupInfoReply->groups = getGroupInfoEnt(groupInfoReq->names, 
						     &num, 
						     recursive);
	    groupInfoReply->numGroups = num;
	    if ( num == 0 || num != groupInfoReq->numNames )
		 
		return (LSBE_BAD_GROUP);
	} 
    }

    return (LSBE_NO_ERROR);

} 
static struct groupInfoEnt *
getGroupInfoEnt(char **groups, int *num, char recursive)
{
    static char              fname[] = "getGroupInfoEnt()"; 
    struct groupInfoEnt *    groupInfoEnt;

    if (groups == NULL) {
	struct uData *u;
	int i;
	
	
	groupInfoEnt = (struct groupInfoEnt *)
	    my_calloc(numofugroups,
		      sizeof(struct groupInfoEnt),
			     fname);

	i = 0;
	
	for (i = 0; i < numofugroups; i++) {
	    struct groupInfoEnt *g;

	    u = getUserData(usergroups[i]->group);
	    
	    g = getGroupInfoEntFromUdata(u, recursive);
	    if (g == NULL) {
		FREEUP(groupInfoEnt);
		lsberrno = LSBE_NO_MEM;
		return (NULL);
	    }
	    memcpy(groupInfoEnt + i, g, sizeof(struct groupInfoEnt));
	}
	  
	*num = numofugroups;        
    } else {             
	struct uData * u;
	int            j = 0;
	int            k;
	int            i;

	groupInfoEnt = (struct groupInfoEnt *)
	    my_calloc(*num, sizeof(struct groupInfoEnt), fname);

	for (i = 0; i < *num; i++) {
	    struct groupInfoEnt *g;
	    bool_t  validUGrp = FALSE;

	    
	    for (k = 0; k < numofugroups; k++) {
		if (strcmp(usergroups[k]->group, groups[i]) == 0) {
		    validUGrp = TRUE;
		    break;
		}
	    }

	    if (validUGrp == FALSE) {
	        struct groupInfoEnt *  tmpgroupInfoEnt;
		lsberrno = LSBE_BAD_USER;
		*num = i;   

		if ( i == 0 )  {  
		    
		    FREEUP(groupInfoEnt);
		    return NULL;
		}

		tmpgroupInfoEnt = (struct groupInfoEnt *)
			my_calloc(i, sizeof(struct groupInfoEnt), fname);

		for(k=0; k < i; k++)
		    tmpgroupInfoEnt[k] = groupInfoEnt[k];
		FREEUP(groupInfoEnt);
		groupInfoEnt = tmpgroupInfoEnt;

		return (groupInfoEnt);
	    }

	    u = getUserData(groups[i]);
	    if (u == NULL) {
		ls_syslog(LOG_ERR, I18N_FUNC_S_FAIL, 
		    fname, "getUserData", groups[i]);
		continue;
	    }
	    
	    g = getGroupInfoEntFromUdata(u, recursive);
	    if (g == NULL){
		lsberrno = LSBE_NO_MEM;
		FREEUP(groupInfoEnt);
		return (NULL);
	    }
	    
	    memcpy(groupInfoEnt + j, g, sizeof(struct groupInfoEnt));
	    
	    j++;           
	}
	*num = j;          
    }
	    
    return (groupInfoEnt);

} 
static struct groupInfoEnt *
getGroupInfoEntFromUdata(struct uData *u, char recursive)
{
    static struct groupInfoEnt group;

    memset((struct groupInfoEnt *)&group, 0, sizeof(struct groupInfoEnt));

    group.group = u->user;
    group.memberList = getGroupMembers(u->gData, 
				      recursive);
    return (&group);

} 
char *
getGroupMembers (struct gData *gp, char r)
{
    char *members;
    int numMembers;

    numMembers = sumMembers(gp, r, 1);
    if (numMembers == 0) {
	members = safeSave("all");        
	return (members);
    }

    members = my_calloc(numMembers, MAX_LSB_NAME_LEN, "getGroupMembers");
    members[0] = '\0';
    catMembers(gp, members, r);
    return members;

} 

int 
sumMembers (struct gData *gp, char r, int first)
{
    int i;
    static int num;
   
    if (first)
	num = 0;

    if (gp->numGroups == 0 && gp->memberTab.numEnts == 0 && r)
        return (0);          

    num += gp->memberTab.numEnts;

    if (!r) 
	num += gp->numGroups;
    else {
	for (i=0; i<gp->numGroups; i++) 
            if (sumMembers (gp->gPtr[i], r, 0) == 0)
                return (0);
    }

    return (num);
} 

static void 
catMembers(struct gData *gp, char *cbuf, char r)
{
    sTab hashSearchPtr;
    hEnt *hashEntryPtr;
    int i;

    hashEntryPtr = h_firstEnt_(&gp->memberTab, &hashSearchPtr);

    while (hashEntryPtr) {
        strcat(cbuf, hashEntryPtr->keyname);
        strcat(cbuf, " ");
        hashEntryPtr = h_nextEnt_(&hashSearchPtr);
    }

    for (i=0;i<gp->numGroups;i++) {
        if (!r) {
            int lastChar = strlen(gp->gPtr[i]->group)-1;
            strcat(cbuf, gp->gPtr[i]->group);
            if ( gp->gPtr[i]->group[lastChar] != '/' ) 
                strcat(cbuf, "/ ");
            else 
                strcat(cbuf, " ");
        } else {
            catMembers(gp->gPtr[i], cbuf, r);
        }
    }
} 

char *
catGnames (struct gData *gp)
{
    int i;
    char *buf;

    if (gp->numGroups <= 0) {
        buf = safeSave(" ");
        return buf;
    }

    buf = my_calloc(gp->numGroups, MAX_LSB_NAME_LEN, "catGnames");
    for (i=0;i<gp->numGroups;i++) {
	strcat (buf, gp->gPtr[i]->group);
	strcat (buf, "/ ");
    }
    return buf;
} 

char **
expandGrp (struct gData *gp, char *gName, int *num)
{
    char **memberTab;

    *num = countEntries(gp, TRUE);
    if (! *num) {
        memberTab = (char **) my_calloc(1, sizeof (char *), "expandGrp");
        memberTab[0] = gName;
        *num = 1;
        return memberTab;
    }
    memberTab = (char **) my_calloc(*num, sizeof (char *), "expandGrp");

    fillMembers(gp, memberTab, TRUE);
    return memberTab;

} 
void 
fillMembers (struct gData *gp, char **memberTab, char first)
{
    sTab hashSearchPtr;
    hEnt *hashEntryPtr;
    static int mcnt;
    int i;

    if (first) {
        first = FALSE;
        mcnt = 0;
    }

    hashEntryPtr = h_firstEnt_(&gp->memberTab, &hashSearchPtr);

    while (hashEntryPtr) {                   
        memberTab[mcnt] = hashEntryPtr->keyname;
        mcnt++;
        hashEntryPtr = h_nextEnt_(&hashSearchPtr);
    }

    for (i=0; i<gp->numGroups; i++)          
        fillMembers(gp->gPtr[i], memberTab, FALSE);

}  
struct gData *
getGroup (int groupType, char *member)
{
    struct gData **gplist;
    int i, ngrp;

    if (groupType == HOST_GRP) {
        gplist = hostgroups;
        ngrp = numofhgroups;
    } else if (groupType == USER_GRP) {
        gplist = usergroups;
        ngrp = numofugroups;
    } else 
        return NULL;

    for (i = 0; i < ngrp; i++) 
        if (gMember(member, gplist[i]))
            return (gplist[i]);

    return NULL;

} 

char
gDirectMember (char *word, struct gData *gp)
{

    if (word == NULL || gp == NULL)
        return FALSE;

    if (gp->numGroups == 0 && gp->memberTab.numEnts == 0)
        return TRUE;    
                        
    if (h_getEnt_(&gp->memberTab, word))
        return TRUE;              
    return FALSE;                           

}                   

 
char
gMember (char *word, struct gData *gp)
{
    int i;

    INC_CNT(PROF_CNT_gMember);

    if (word == NULL || gp == NULL)
        return FALSE;

    if (gDirectMember(word, gp))
        return TRUE;

    for (i = 0; i < gp->numGroups; i++) {
        if (gMember(word, gp->gPtr[i]))
            return TRUE;
    }
    return FALSE;

} 


int
countEntries (struct gData *gp, char first)
{
    static int num;
    int i;

    if (first)
        num = 0;

    num += gp->memberTab.numEnts;   

    for (i=0;i<gp->numGroups;i++)
        countEntries(gp->gPtr[i], FALSE);

    return num;

} 

struct gData *
getUGrpData (char *gname)
{
    return (getGrpData (usergroups, gname, numofugroups));
} 

struct gData *
getHGrpData (char *gname)
{
    return (getGrpData (hostgroups, gname, numofhgroups));
} 

struct gData *
getGrpData (struct gData *groups[], char *name, int num)
{
    int i;

    if (name == NULL)
        return NULL;

    for (i = 0; i < num; i++) {
        if (strcmp (name, groups[i]->group) == 0)
            return (groups[i]);
    }

    return NULL;

} 

void
uDataGroupCreate()
{
    static char fname[] = "uDataGroupCreate()";
    int i;

    for (i = 0; i < numofugroups; i++) {
	struct uData *u;
	
	
	if ((u = getUserData(usergroups[i]->group)) == NULL) {
	    ls_syslog(LOG_ERR, I18N_FUNC_S_FAIL_M, 
		fname, "getUserData", usergroups[i]->group);
	    mbdDie(MASTER_FATAL);
	}
	u->flags |= USER_GROUP;
	
	if (logclass & (LC_TRACE))
	    ls_syslog(LOG_DEBUG2, "\
%s: removing user group <%s> from all user set",
		      fname, u->user);
	
	setRemoveElement(allUsersSet, (void *)u);
	
	if (USER_GROUP_IS_ALL_USERS(usergroups[i]) == TRUE) {
	    u->flags |= USER_ALL;
	    
            if(u->children){
	    setDestroy(u->children);
            }
            if(u->descendants){
	    setDestroy(u->descendants);
            }

	    u->children = allUsersSet;
	    u->descendants = allUsersSet;
	    setAddElement(uGrpAllSet, (void *)u);
	}

	
	u->gData = usergroups[i];
	
    }
} 
void
uDataPtrTbInitialize(void)
{
    sTab        hashSearchPtr;
    hEnt *      hashEntryPtr;
    int         currentIndex;

    uDataPtrTb = uDataTableCreate();

    currentIndex = 0;
    hashEntryPtr = h_firstEnt_(&uDataList, &hashSearchPtr);
    
    while (hashEntryPtr) {
	struct uData *uData;

	uData = (struct uData *)hashEntryPtr->hData;

	uData->uDataIndex = currentIndex;
	++currentIndex;
        
	
	uDataTableAddEntry(uDataPtrTb, uData);

	
	hashEntryPtr = h_nextEnt_(&hashSearchPtr);	
    }

}
int
getIndexByuData(void *userData)
{
    struct uData *u;

    u = (struct uData *)userData;

    return (u->uDataIndex);
}

void *
getuDataByIndex(int index)
{
    if (index > uDataPtrTb->_size_)
	return (NULL);

    return ((struct uData *)uDataPtrTb->_base_[index]); 
}
void
setuDataCreate()
{
    static char fname[] = "setuDataCreate";
    struct uData *u;

    while ((u = uDataTableGetNextEntry(uDataPtrTb))) {
	if ((u->flags & USER_GROUP) 
	    && (strncmp(u->user, "others", 6) != 0)) {
	    
	    traverseGroupTree(u->gData);
        }
    }

    
    while ((u = uDataTableGetNextEntry(uDataPtrTb)) != NULL)
    {
	
	if (! u->flags & USER_GROUP) {
	    struct uData              *allUserGrp;
	    LS_BITSET_ITERATOR_T      iter;

	    BITSET_ITERATOR_ZERO_OUT(&iter);
	    setIteratorAttach(&iter, uGrpAllSet, fname);
	    for (allUserGrp = (struct uData *)setIteratorBegin(&iter);
		 allUserGrp != NULL;
		 allUserGrp = (struct uData *)setIteratorGetNextElement(&iter))
	    {
		setAddElement(u->parents, (void *)allUserGrp);
		setAddElement(u->ancestors, (void *)allUserGrp);
	    }
	}
	
	if (u->flags & USER_ALL) 
	    FOR_EACH_USER_ANCESTOR_UGRP(u, ancestor) {
	        if (setIsMember(uGrpAllAncestorSet, (void *)ancestor)==FALSE)
		{
		    char                      strBuf[512];
		    LS_BITSET_OBSERVER_T      *observer;

		    
		    sprintf(strBuf,
			    "User <%s>'s all user set observer",
			    ancestor->user);
		    
		    observer = setObserverCreate(strBuf,
						 (void *)ancestor->descendants,
						 (LS_BITSET_ENTRY_SELECT_OP_T)
						 NULL,
						 LS_BITSET_EVENT_ENTER,
						 userSetOnNewUser,
						 LS_BITSET_EVENT_NULL);
		    if (observer == NULL) {
			ls_syslog(LOG_ERR, _i18n_msg_get(ls_catd , NL_SETN, 5902,
			    "%s: failed to create observer for all users set: %s"), /* catgets 5902 */
			    fname, setPerror(bitseterrno));
			mbdDie(MASTER_FATAL);
		    }

		    setObserverAttach(observer, allUsersSet);
		    setAddElement(uGrpAllAncestorSet, ancestor);
		}
            } END_FOR_EACH_USER_ANCESTOR_UGRP;
    }    
}
static void
traverseGroupTree(struct gData *grp)
{
    static char         fname[] = "traverseGroupTree";
    struct uStackEntry  uStack[MAX_GROUPS]; 
    int                 uStackTop;
    int                 uStackCur;

    uStackTop = 0;
    uStackCur = -1;

    
    uStack[uStackTop].myGData = grp;
    uStack[uStackTop].myUData = getUserData(grp->group);
    uStack[uStackTop].parentGData = NULL;
    uStack[uStackTop].parentUData = NULL;

    ++uStackTop;
    uStackCur = 0;

    while (uStackCur < uStackTop) {
        int i;
        struct gData *curGData;
        struct uData *curUData;
	sTab hashSearchPtr;
	hEnt *hashEntryPtr;

        
        curGData = uStack[uStackCur].myGData;
        curUData = uStack[uStackCur].myUData;

	
	checkuDataSet(curUData);

	
	hashEntryPtr = h_firstEnt_(&curGData->memberTab, &hashSearchPtr);
	
	while (hashEntryPtr) {
	    char *user;
	    struct uData *u;
	    
	    user =  hashEntryPtr->keyname;

	    u = getUserData(user);
	    if (u == NULL) {
		ls_syslog(LOG_ERR, I18N_FUNC_S_FAIL, 
		    fname, "getUserData", user);
		continue;
	    }
	    
	    
	    checkuDataSet(u);
	    
	    
	    setAddElement(u->parents, curUData);
	    setAddElement(u->ancestors, curUData);
	    
	    
	    setOperate(u->ancestors, curUData->ancestors,
		       LS_SET_UNION);
		
	    
	    setAddElement(curUData->children, u);
	    setAddElement(curUData->descendants, u);
	    
	    
	    hashEntryPtr = h_nextEnt_(&hashSearchPtr);
	}
	
	
	for (i = 0; i < curGData->numGroups; i++) {
	    struct gData *subGData;  
	    struct uData *subUData;
	    
	    subGData = curGData->gPtr[i];
	    subUData = getUserData(subGData->group);
	    
	    uStack[uStackTop].myGData = subGData;
	    uStack[uStackTop].myUData = subUData;
	    uStack[uStackTop].parentGData = curGData;
	    uStack[uStackTop].parentUData = curUData;
	    
	    
	    checkuDataSet(subUData);
	    
	    
	    setAddElement(subUData->parents, curUData);
	    setAddElement(subUData->ancestors, curUData);
	    setOperate(subUData->ancestors, curUData->ancestors, 
		       LS_SET_UNION);

	    
	    setAddElement(curUData->children, subUData);
	    setAddElement(curUData->descendants, subUData);
	    
	    ++uStackTop;
	}

	++uStackCur;
    }
    
    --uStackTop;
    while (uStackTop > 0 ) {
        struct uData *curUData;
	struct uData *parentUData;
	
        curUData = uStack[uStackTop].myUData;
	parentUData = uStack[uStackTop].parentUData;

 	
	checkuDataSet(parentUData);

	setOperate(parentUData->descendants, curUData->descendants, 
		   LS_SET_UNION);

        --uStackTop;
    }
}
static void 
checkuDataSet(struct uData *u)
{
    static char fname[] = "checkuDataSet()";
    static char strBuf[128];

    if (u->children == NULL) {
	memset(strBuf, 0, 128);
	sprintf(strBuf, "%s children set", u->user);
	u->children = setCreate(MAX_GROUPS, 
				getIndexByuData, 
				getuDataByIndex ,
				strBuf);
    }

    if (u->descendants == NULL) {
	memset(strBuf, 0, 128);
	sprintf(strBuf, "%s descendants set", u->user);
	u->descendants = setCreate(MAX_GROUPS, 
				 getIndexByuData, 
				 getuDataByIndex ,
				 strBuf);
    }

    if (u->parents == NULL) {
	memset(strBuf, 0, 128);
	sprintf(strBuf, "%s parents set", u->user);
	u->parents = setCreate(MAX_GROUPS, 
			       getIndexByuData, 
			       getuDataByIndex ,
			       strBuf);
    }

    if (u->ancestors == NULL) {
       	memset(strBuf, 0, 128);
	sprintf(strBuf, "%s ancestors set", u->user);
	u->ancestors = setCreate(MAX_GROUPS, 
				getIndexByuData, 
				getuDataByIndex ,
				strBuf);
    }
    if (u->children == NULL   ||
	u->descendants == NULL||
	u->parents == NULL    ||
	u->ancestors == NULL) {
	ls_syslog(LOG_ERR, _i18n_msg_get(ls_catd , NL_SETN, 5904,
	    "%s: Failed in creating user set %s"), /* catgets 5904 */
	    fname, 
	    setPerror(bitseterrno));
	mbdDie(MASTER_FATAL);
    }
}
UDATA_TABLE_T *
uDataTableCreate()
{
    static char fname[] = "uDataTableCreate()";
    UDATA_TABLE_T *this;

    this = (UDATA_TABLE_T *)my_calloc(1, sizeof(UDATA_TABLE_T), fname);

    this->_base_ = (struct uData **)my_calloc(MAX_GROUPS,
						sizeof(struct uData *),
						fname);
    this->_cur_  =   0;
    this->_size_ =   MAX_GROUPS;

    return (this);

} 

void 
uDataTableFree(UDATA_TABLE_T *uTab)
{

    if (!uTab)
       return;
    FREEUP(uTab->_base_)
    FREEUP(uTab);
    return;

} 

void
uDataTableAddEntry(UDATA_TABLE_T *this, struct uData *new)
{
    static char fname[] = "uDataTableAddEntry()";

    if (! this) {
	this = uDataPtrTb = uDataTableCreate();
    }

    if (this->_cur_  >= this->_size_) {

	this->_base_ = (struct uData **)realloc(this->_base_,
						2*(this->_size_)
						*(sizeof(struct uData *)));
	if (this->_base_ == NULL) {
	    ls_syslog(LOG_ERR, I18N_FUNC_FAIL_M, fname, "realloc");
	    mbdDie(MASTER_FATAL);
	}
			
	memset(this->_base_ + this->_size_, 0, 
	       (this->_size_)*(sizeof(struct uData *)));
	this->_size_ = 2*(this->_size_);
    }

    this->_base_[this->_cur_++] = new ;

} 
int
uDataTableGetNumEntries(UDATA_TABLE_T *this)
{
    return(this->_size_);
}
struct uData *
uDataTableGetNextEntry(UDATA_TABLE_T *this)
{
    static int i = 0;

    if (i == this->_cur_) {
	i = 0;
	return (NULL);
    } else {
	return (this->_base_[i++]);
    }
}

int
userSetOnNewUser(LS_BITSET_T *subjectSet, 
		 void *extra, 
		 LS_BITSET_EVENT_T *event)
{
    static char        fname[] = "userSetOnNewUser";
    LS_BITSET_T        *set;
    struct uData       *newUser;

    set = (LS_BITSET_T *) extra;
    newUser = (struct uData *)event->entry;

    if (logclass & (LC_TRACE)) 
	ls_syslog(LOG_DEBUG, "\
%s: added new user <%s> to <%s>", 
		  fname, newUser->user,  set->setDescription);
	
    setAddElement(set, (void *)newUser);

    return (0);

} 

#define SKIP_HOST_GROUP(group) (strstr(group, "others") != NULL)

static void
getAllHostGroup(struct gData **gplist, int ngrp, int recursive,
		struct groupInfoEnt *groupInfoEnt, int *numHostGroup)
{
    int i, count;
    
    for (i = 0, count = 0; i < ngrp; i++) {
	if (SKIP_HOST_GROUP(gplist[i]->group)) {
	    continue;
	}
	copyHostGroup(gplist[i], recursive,
		      &(groupInfoEnt[count]));
	count++;
    }
    *numHostGroup = count;
}

static void 
getSpecifiedHostGroup(char **grpName, int numGrpName, struct gData **gplist, 
		      int ngrp, int recursive, 
		      struct groupInfoEnt *groupInfoEnt, int *numHostGroup)
{
    int i, count;
    
    for (count = 0; count < numGrpName; count++) {
	int groupFound = FALSE;
	
	for (i = 0; i < ngrp; i++) {
	    if (SKIP_HOST_GROUP(gplist[i]->group)) {
		continue;
	    }
	    if (strcmp(gplist[i]->group, grpName[count]) == 0) {
		groupFound = TRUE;
		break;
	    }
	}
	if (groupFound) {
	    copyHostGroup(gplist[i], recursive,
			  &(groupInfoEnt[count]));
	} else {
	    
	    break;
	}
    }
    *numHostGroup = count;
}
	    
static void
copyHostGroup(struct gData *grp, int recursive, 
	      struct groupInfoEnt *groupInfoEnt)
{
    groupInfoEnt->group = grp->group;
    groupInfoEnt->memberList = getGroupMembers(grp, recursive);
}

int
sizeofGroupInfoReply(struct groupInfoReply *ugroups) 
{
    int              len;
    int              i;

    len = 0;

    
    len += ALIGNWORD_(sizeof(struct groupInfoReply) 
		      + ugroups->numGroups * sizeof(struct groupInfoEnt)
		      + ugroups->numGroups * NET_INTSIZE_);
    
    for (i = 0; i < ugroups->numGroups; i++) {
	struct groupInfoEnt      *ent;
	
	ent = &(ugroups->groups[i]);
	
	
	len += ALIGNWORD_(strlen(ent->group) + 1);
	len += ALIGNWORD_(strlen(ent->memberList) + 1);
    }

    return(len);

} 
